iT邦幫忙

2022 iThome 鐵人賽

DAY 11
0
自我挑戰組

跟著 Go 實戰聖經 一起自學 Go系列 第 11

DAY 11 Go 語言 的核心型別 - 數字

  • 分享至 

  • xImage
  •  

不知道大家會不會有跟我一樣的問題,為什麼還要特別介紹型別?鐵人賽都第八天了,我多少也知道有 string (字串)、bool (布林值)、int (數字)等,還有需要特別用一天的鐵人賽來介紹嗎?
答案是:「需要!」,至於為什麼呢?記得我們在鐵人賽第一天介紹 Go 語言時,就有說過他是一種 強型別的語言強型別的語言 就是遇到函式引數型別和實際叫用型別不符合的情況,是會直接 出錯 或者 編譯失敗 的。也因為如此在 Go 語言中型別是很重要的,我們要先搞清楚各個型別,讓正確的型別放在函數引數中,就可以避免不必要的錯誤發生。

型別的定義

  1. 可以儲存哪種資料 例: int 可以儲存正負數(後面就會詳細介紹呦~)
  2. 可以對資料做哪種操作 例: 可以對 int 做運算(加減乘除等等)
  3. 操作後,會對資料做什麼 例: 對 int 做運算後,是否改變原變數的值
  4. 會佔用多少記憶體 例:若今天確定儲存的數字為 0~255 之間,可以使用 uint8 的型別,來節省記憶體空間

接下來就先從數字型別開始介紹起吧!

數字

在 Go 語言中有分兩種數字:

  1. 整數(integers):整數即包含正整數與負整數。
  2. 浮點數(floating-point numbers):浮點數即是由整數和小數位組成的。

而無論是哪種數字的零值皆為 0

整數(integers)

而整數內又分為兩種:

  1. 有號整數:可以存正整數及負整數的型別。
  2. 無號整數:只能存正整數的型別。

其中又根據其內部的儲存容量分為以下幾種型別:

型別 解釋 範圍
uint8 = (byte) 無號 8 位元整數 0 ~ 255
uint16 無號 16 位元整數 0 ~ 65535
uint32 = (rune) 無號 32 位元整數 0 ~ 4294967295
uint64 無號 64 位元整數 0 ~ 18446744073709551615
uint 無號 32 或 64 位元整數 0 ~ 4294967295 或 0 ~ 18446744073709551615
int8 有號 8 位元整數 -128 ~ 127
int16 有號 16 位元整數 -32768 ~ 32767
int32 有號 32 位元整數 -2147483648 ~ 2147483647
int64 有號 64 位元整數 -9223372036854775808 ~ 9223372036854775807
int 有號 32 或 64 位元整數 -2147483648 ~ 2147483647 或 -9223372036854775808 ~ 9223372036854775807

看到以上有這麼多型別是不是眼花撩亂?(要我全部背起來根本不可能),正常來說我們若要定義變數的型別時,較常使用 int ,但也總會遇到使用 int 有錯誤發生的時候,通常這種錯誤都是因為記憶體耗盡的關係,那只需要確認一下您宣告的變數內的值,若您確定他一定會是 < 255 的正整數,那你只需要將型別改成 uint8 即可以解決記憶體的問題。

浮點數(floating-point numbers)

在 Go 語言中浮點數也分為兩種

  1. float32:使用 32 位元來儲存數值,容量較小、精確度較低。
  2. float64:使用 64 位元來儲存數值,容量較大、精確度較高。

正常來說會優先使用 float64 ,因為精確度較高,同上,若是遇到記憶體空間不足時,才會選用 float32 。

範例 1:

package main

import "fmt"

func main(){
    var x int = 1000
    var y float32 = 1000
    var z float64 = 1000

    fmt.Println("int:",x/7) // 整數除整數得整數
    fmt.Println("float32",y/7) // 整數除浮點數得浮點數
    fmt.Println("float64",z/7) 
}

範例 1(執行結果):

int: 142
float32 142.85715
float64 142.85714285714286 // 與前者差別在於精確度

補充:
雖然說 float64 準確度較高,但他並不是完全準確的,因為電腦是用二進位制來儲存小數,故多少還是會有些微誤差的,只是可能他在小數後好幾位,所以並不太影響正常運算功能。但若是重複計算的話,微小的誤差也可能被放大。

範例 2:

package main

import "fmt"

func main(){
    var x int = 1000
    var y float32 = 1000
    var z float64 = 1000

    fmt.Println("int:",x/7*7/7*7)
    fmt.Println("float32",y/7*7/7*7)
    fmt.Println("float64",z/7*7/7*7)
}

範例 2(執行結果):

int: 994
float32 1000
float64 1000

溢位 (overflows)

如果今天你很調皮?!硬是宣告一個超過型別範圍的值,則會產生溢位的錯誤。如: uint8 最大就是 255 ,你硬是宣告一個 256 ,那我們來看看會發生什麼事吧^^

範例 3:

package main

import "fmt"

func main(){
    var x uint8 = 256 // 硬宣告一個超過型別範圍的值

    fmt.Println("uint8:",x)
}

範例 3(執行結果):

cannot use 256 (untyped int constant) as uint8 value in variable declaration (overflows)

這邊錯誤訊息告訴你不能用 256 ,因為在 uint8 已經 overflows 了!
當看到這個錯誤訊息時還好解決,我們只需要確認一下是不是定義一個超出 uint8 範圍的變數,再做修正及可。

越界繞回 (wraparound)

溢位還好解決,但當你今天先定義變數後,才賦予一個超過型別範圍的值給他,就不是溢位這麼簡單了,會發生 越界繞回 的問題。如: uint8 最大就是 255 ,你先是宣告一個值為 253 的 uint8 ,然後在後面因為運算等等,將其變數修改為大於 255 的數 ,因為這個變數已經超過最大值,那他便會從最小值開始重新起算,如果用文字敘述有些難理解,直接看範例吧!

範例 4:

package main

import "fmt"

func main(){
    var x uint8 = 253

    for i := 0; i < 5; i++{
        x++ // 每次迴圈 x 的值加一
        fmt.Println("uint8:",x) // 超過 255 即從最小值 0 起算
    }
}

範例 4(執行結果):

uint8: 254
uint8: 255
uint8: 0
uint8: 1
uint8: 2

因為越界繞回並不會像溢位一樣直接噴錯,所以很多時候發生越界繞回時是很難除錯的,所以當我們在對於變數做運算時,一定要確認一下其型別的最大最小值,以避免發生越界繞回的問題。

大數值

如果今天你要宣告一個極大或極小的數,而這個數早已大於或小於 uint64 或 int64 的範圍,可以使用內建套件 math/big,直接使用範例來看看

範例 5:

package main

import (
	"fmt"
	"math"
	"math/big"
)

func main(){
    maxInt := math.MaxInt64 // 最大 int 整數
    maxInt = maxInt + 1 

    bigInt := big.NewInt(math.MaxInt64)
    bigInt.Add(bigInt,big.NewInt(1))
    
    fmt.Println("原本的maxInt:",math.MaxInt64)
    fmt.Println("加1後的maxInt:",maxInt)
    fmt.Println("加1後的bigInt:",bigInt)
}

範例 5(執行結果):

原本的maxInt: 9223372036854775807
加1後的maxInt: -9223372036854775808 // 因為原本的 maxInt 已是最大值,加一後發生越界繞回
加1後的bigInt: 9223372036854775808  // 但使用 math/big 內建套件,即可順利加一

不知道大家有沒有跟我一樣的想法:「天阿光是數字怎麼會那麼複雜啦QQ」,但是在搞懂各個數字型別後,才可以讓未來的自己少走冤望路呀,畢竟 Go 是一個強型別的語言,型別錯誤就會報錯的!那我們明天繼續介紹在 Go 語言中的其他核心型別吧~


上一篇
DAY 10 Go 語言 迴圈的使用
下一篇
DAY 12 Go 語言 的核心型別 - 布林值 (Boolean) 、字串 (String) 及 nil 值
系列文
跟著 Go 實戰聖經 一起自學 Go30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言